/**
 * Copyright 2019 吉鼎科技.

 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package cn.easyplatform.engine.runtime.jasper;

import cn.easyplatform.EasyPlatformWithLabelKeyException;
import cn.easyplatform.ScriptRuntimeException;
import cn.easyplatform.contexts.ListContext;
import cn.easyplatform.contexts.RecordContext;
import cn.easyplatform.contexts.ReportContext;
import cn.easyplatform.contexts.WorkflowContext;
import cn.easyplatform.dos.FieldDo;
import cn.easyplatform.engine.executor.ExecutorFactory;
import cn.easyplatform.engine.runtime.ComponentProcess;
import cn.easyplatform.engine.runtime.jxls.JxlsReportProcess;
import cn.easyplatform.entities.beans.report.JasperReportBean;
import cn.easyplatform.interceptor.CommandContext;
import cn.easyplatform.lang.Strings;
import cn.easyplatform.messages.vos.ReportVo;
import cn.easyplatform.type.DeviceType;
import cn.easyplatform.type.FieldType;
import cn.easyplatform.util.RuntimeUtils;
import net.sf.jasperreports.engine.JRException;
import net.sf.jasperreports.engine.JasperPrint;
import net.sf.jasperreports.engine.JasperReport;
import org.apache.commons.lang3.SerializationUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/**
 * @author <a href="mailto:davidchen@epclouds.com">littleDog</a> <br/>
 * @since 2.0.0 <br/>
 */
public class JasperReportProcess implements
        ComponentProcess<JasperReportBean, ReportVo, JasperPrint> {

    private final static Logger log = LoggerFactory.getLogger(JasperReportProcess.class);

    @Override
    public JasperPrint doComponent(CommandContext cc, ReportVo rv,
                                   JasperReportBean entity) {
        if (entity.getReportModel() == null)
            throw new EasyPlatformWithLabelKeyException(
                    "report.entity.no.compile", entity.getId());
        JasperReport jr = (JasperReport) entity.getReportModel();
        try {
            WorkflowContext ctx = cc.getWorkflowContext();
            ReportContext report = ctx.setReport(rv.getId(), rv.getEntityId(),
                    rv.getIds(), rv.getState(), entity.getTable());
            if (rv.getState() == 'U' || rv.getState() == 'R') {
                StringBuilder sb = new StringBuilder();
                for (String name : rv.getIds().split(","))
                    sb.append(ctx.getRecord().getValue(name));
                List<FieldDo> params = new ArrayList<FieldDo>();
                FieldDo fd = new FieldDo(FieldType.VARCHAR);
                fd.setValue(report.getEntityId());
                fd.setName("reportid");
                params.add(fd);
                fd = new FieldDo(FieldType.VARCHAR);
                fd.setValue(sb.toString());
                fd.setName("bizid");
                params.add(fd);
                FieldDo obj = cc
                        .getBizDao()
                        .selectObject(
                                "select content from sys_report_log where reportid=? and bizid=?",
                                params);
                if (obj != null)
                    return (JasperPrint) SerializationUtils.deserialize((byte[]) obj
                            .getValue());
                if (rv.getState() == 'R')// 如果是R类型找不到对应的记录就出错
                    throw new EasyPlatformWithLabelKeyException(
                            "report.print.not.found", report.getEntityId(), sb);
            }
            if ((jr.getQuery() != null && jr.getQuery().getChunks() != null)
                    || !Strings.isBlank(entity.getQuery())) {// 自定义
                if (!Strings.isBlank(rv.getInit())) {
                    if (!Strings.isBlank(entity.getQuery())) {
                        if (entity.getQuery().startsWith("$"))
                            entity.setQuery((String) ctx.getRecord().getValue(entity.getQuery().substring(1).trim()));
                    }
                    if (Strings.isBlank(entity.getQuery())) {
                        RecordContext rc = ctx.getRecord();
                        Collection<ListContext> lists = ctx.getLists();
                        String code = RuntimeUtils.eval(cc, rv.getInit(), rc);
                        if (!code.equals("0000"))
                            throw new ScriptRuntimeException(code,
                                    cc.getMessage(code, ctx.getRecord()));
                        JasperPrint print = new CustomReportHandler(cc, rc, lists,
                                entity, rv).doReport(jr);
                        //if (!Strings.isBlank(report.getIds()))
                            report.setPrint(print);
                        return print;
                    }
                }
                DeviceType dt = cc.getUser().getDeviceType();
                try {
                    if (rv.getShowProgress() != null && !rv.getShowProgress())
                        cc.getUser().setDeviceType(DeviceType.JOB);
                    return (JasperPrint) ExecutorFactory.createReportExecutor(
                            entity).exec(cc, entity, rv);
                } finally {
                    cc.getUser().setDeviceType(dt);
                }
                // new QueryReportHandler(cc, entity).doReport(jr);
            } else {
                RecordContext rc = null;
                Collection<ListContext> lists = null;
                if (!Strings.isBlank(rv.getFrom())) {
                    if (NumberUtils.isNumber(rv.getFrom())) {
                        int layer = NumberUtils.toInt(rv.getFrom());
                        rc = ctx.getRecordContext(layer);
                        lists = ctx.getLists(layer);
                    } else if (rv.getFrom().indexOf("->") > 0) {
                        // 分层下的EMBBED数据源
                        int pos = rv.getFrom().indexOf("->");
                        int layer = NumberUtils.toInt(rv.getFrom().substring(0,
                                pos));
                        String cid = rv.getFrom().substring(pos + 2);
                        String id = ctx.getTask(layer, cid);
                        if (id == null)
                            throw new EasyPlatformWithLabelKeyException(
                                    "task.not.found.from.layer", layer, id);
                        WorkflowContext wc = cc.getWorkflowContext(id);
                        if (wc == null)
                            throw new EasyPlatformWithLabelKeyException(
                                    "task.not.found.from.layer", layer, id);
                        rc = wc.getRecord();
                        lists = wc.getLists();
                    } else {// 当前层下的EMBBED数据源
                        String id = ctx.getTask(rv.getFrom());
                        if (id == null)
                            throw new EasyPlatformWithLabelKeyException(
                                    "task.not.found.from.layer",
                                    ctx.getParameter("828"), id);
                        WorkflowContext wc = cc.getWorkflowContext(id);
                        if (wc == null)
                            throw new EasyPlatformWithLabelKeyException(
                                    "task.not.found.from.layer",
                                    ctx.getParameter("828"), id);
                        rc = wc.getRecord();
                        lists = wc.getLists();
                    }
                } else {
                    rc = ctx.getRecord();
                    lists = ctx.getLists();
                    if (!Strings.isBlank(rv.getInit())) {// 从逻辑中获取
                        String code = RuntimeUtils.eval(cc, rv.getInit(), rc);
                        if (!code.equals("0000"))
                            throw new ScriptRuntimeException(code,
                                    cc.getMessage(code, ctx.getRecord()));
                    }
                }
                JasperPrint print = new CustomReportHandler(cc, rc, lists,
                        entity, rv).doReport(jr);
                //if (!Strings.isBlank(report.getIds()))
                    report.setPrint(print);
                return print;
            }
        } catch (Exception ex) {
            if (log.isErrorEnabled())
                log.error("doComponent", ex);
            throw new EasyPlatformWithLabelKeyException("report.fill.error",
                    ex, entity.getId(), ex.getMessage());
        }
    }

}
